import os
import logging
from watchdog.events import FileSystemEventHandler
from file_syncer import FileSyncer
from database import db_manager
import threading
import time

class SyncHandler(FileSystemEventHandler):
    def __init__(self, sync_dir_id, ignore_patterns):
        super().__init__()
        self.sync_dir_id = sync_dir_id
        self.ignore_patterns = ignore_patterns
        self.syncer = None
        self.observer_schedule = None
        self.sync_logger = logging.getLogger('sync')
        self._init_syncer()
        self._event_times = {}  # 用于跟踪事件时间
        self._event_cooldown = 3.0  # 增加事件冷却时间到3秒
        self._last_file_sizes = {}  # 用于存储文件大小

    def _init_syncer(self):
        """初始化同步器"""
        try:
            if not self.syncer:
                self.syncer = FileSyncer(self.sync_dir_id, db_manager.get_db_path())
        except Exception as e:
            self.sync_logger.error(f"初始化同步器失败: {str(e)}")
            raise

    def _should_ignore(self, path):
        """检查是否应该忽略此路径"""
        basename = os.path.basename(path)
        return any(pattern in basename for pattern in self.ignore_patterns)

    def get_relative_path(self, path):
        """获取相对于同步目录的路径，并过滤掉无效路径"""
        try:
            if not self.syncer:
                self._init_syncer()
            base_path = self.syncer.sync_info['local_path']
            rel_path = os.path.relpath(path, base_path)

            # 检查路径有效性
            if self.is_invalid_path(rel_path):
                self.sync_logger.warning(f"跳过无效路径: {rel_path}")
                return None

            return rel_path
        except Exception as e:
            self.sync_logger.error(f"获取相对路径失败: {str(e)}")
            raise

    def is_invalid_path(self, path):
        """检查路径是否无效，过滤掉系统可能误报的路径"""
        try:
            # 完全排除已知的错误目录名
            invalid_patterns = [
                '脰脨脦脛脛脴',  # 已知的错误目录名
                '\xc3', '\xbc', '\xd6',  # 无效编码序列
                '脰', '脨', '脦', '脛', '脴'  # 错误编码的中文字符
            ]

            # 直接匹配已知的错误模式
            for pattern in invalid_patterns:
                if pattern in path:
                    self.sync_logger.warning(f"路径包含已知的无效模式 '{pattern}': {path}")
                    return True

            # 尝试用不同编码解码再编码，测试是否有效
            encodings = ['utf-8', 'gbk', 'gb2312']
            all_failed = True

            for encoding in encodings:
                try:
                    # 尝试编码解码以检查是否有效
                    path.encode(encoding).decode(encoding)
                    all_failed = False
                    break
                except UnicodeError:
                    continue

            if all_failed:
                self.sync_logger.warning(f"路径在所有编码下都无效: {path}")
                return True

            # 检查是否包含控制字符
            if any(ord(c) < 32 for c in path):
                self.sync_logger.warning(f"路径包含控制字符: {path}")
                return True

            return False  # 默认路径有效
        except Exception as e:
            self.sync_logger.error(f"检查路径有效性时出错: {str(e)}")
            return True  # 出错时认为路径无效

    def _retry_operation(self, operation, max_retries=3):
        """重试操作"""
        last_error = None
        for attempt in range(max_retries):
            try:
                if not self.syncer:
                    self._init_syncer()
                return operation()
            except Exception as e:
                last_error = e
                self.sync_logger.warning(f"操作失败，尝试重试 ({attempt + 1}/{max_retries}): {str(e)}")
                self.syncer = None  # 重置同步器
                if attempt == max_retries - 1:
                    self.sync_logger.error(f"操作失败，已达到最大重试次数: {str(e)}")
                    raise last_error
                time.sleep(1)  # 等待1秒后重试

    def _should_process_event(self, event_path, event_type):
        """检查是否应该处理此事件"""
        current_time = time.time()
        event_key = f"{event_path}:{event_type}"

        # 特殊处理临时文件
        if os.path.basename(event_path).startswith('.tmp_'):
            self.sync_logger.info(f"跳过临时文件事件: {event_path}")
            return False

        # 检查最近是否处理过相同的事件
        if event_key in self._event_times:
            last_time = self._event_times[event_key]
            time_diff = current_time - last_time
            if time_diff < self._event_cooldown:
                self.sync_logger.info(
                    f"跳过事件处理，冷却期内 ({time_diff:.2f}s < {self._event_cooldown}s): {event_path}")
                return False

            # 对于修改事件，增加额外的冷却时间检查，防止循环同步
            if event_type == 'modified' and time_diff < self._event_cooldown * 2:
                # 检查文件大小是否变化，如果没有变化，可能是同步操作导致的修改事件
                try:
                    if os.path.exists(event_path):
                        current_size = os.path.getsize(event_path)
                        if hasattr(self, '_last_file_sizes') and event_path in self._last_file_sizes:
                            if current_size == self._last_file_sizes[event_path]:
                                self.sync_logger.info(f"跳过修改事件，文件大小未变化: {event_path}")
                                return False

                        # 记录当前文件大小
                        if not hasattr(self, '_last_file_sizes'):
                            self._last_file_sizes = {}
                        self._last_file_sizes[event_path] = current_size
                except Exception as e:
                    self.sync_logger.error(f"检查文件大小失败: {str(e)}")

        # 特殊处理删除和创建事件的序列
        # 如果短时间内同一文件先删除后创建，可能是替换操作，应该只处理创建事件
        if event_type == 'deleted':
            # 标记此文件已被删除，等待可能的创建事件
            if not hasattr(self, '_deleted_files'):
                self._deleted_files = {}
            self._deleted_files[event_path] = current_time

        elif event_type == 'created':
            # 检查此文件是否刚刚被删除过
            if (hasattr(self, '_deleted_files') and
                    event_path in self._deleted_files and
                    current_time - self._deleted_files[event_path] < self._event_cooldown * 2):
                self.sync_logger.info(f"检测到文件替换操作，跳过删除事件，只处理创建事件: {event_path}")
                # 从删除文件列表中移除
                del self._deleted_files[event_path]

        # 更新事件时间
        self._event_times[event_key] = current_time

        # 清理旧的事件记录
        self._event_times = {k: v for k, v in self._event_times.items()
                             if current_time - v < self._event_cooldown * 5}  # 保留更长时间的历史

        # 清理旧的删除文件记录
        if hasattr(self, '_deleted_files'):
            self._deleted_files = {k: v for k, v in self._deleted_files.items()
                                   if current_time - v < self._event_cooldown * 3}

        return True

    def _should_sync(self):
        """检查是否应该执行同步操作

        如果用户尚未选择同步策略（即策略为None或空字符串），则不执行同步
        """
        try:
            if not self.syncer:
                self._init_syncer()

            # 检查同步策略是否已设置
            strategy = self.syncer.sync_info.get('sync_strategy')
            self.sync_logger.info(f"当前同步策略: {strategy} (dir_id={self.sync_dir_id})")

            if not strategy or strategy == 'none':
                self.sync_logger.info(f"用户尚未选择同步策略，不执行同步操作 (dir_id={self.sync_dir_id})")
                return False

            return True
        except Exception as e:
            self.sync_logger.error(f"检查同步策略失败: {str(e)}")
            return False

    def on_created(self, event):
        """处理创建事件"""
        if self._should_ignore(event.src_path):
            return

        if not self._should_process_event(event.src_path, 'created'):
            return

        try:
            rel_path = self.get_relative_path(event.src_path)
            self.sync_logger.info(f"开始处理创建事件: path={event.src_path}, is_directory={event.is_directory}")

            # 检查是否应该执行同步
            if not self._should_sync():
                self.sync_logger.info(f"跳过同步，等待用户选择同步策略 (path={event.src_path})")
                return

            # 检查同步策略
            if not self.syncer:
                self._init_syncer()
            strategy = self.syncer.sync_info['sync_strategy']

            # 检查是否是文件替换操作的一部分
            is_replacement = False
            if (hasattr(self, '_deleted_files') and event.src_path in self._deleted_files):
                is_replacement = True
                self.sync_logger.info(f"检测到文件替换操作，处理创建事件: {rel_path}")
                # 从删除文件列表中移除
                del self._deleted_files[event.src_path]

            if strategy == 'server_priority':
                # 服务器优先：检查服务器文件并同步到本地
                try:
                    if not event.is_directory:
                        try:
                            self._retry_operation(lambda: self.syncer.sync_from_server(rel_path))
                        except Exception as e:
                            if 'No such file' in str(e) or '550' in str(e):  # 文件不存在
                                # 如果服务器上不存在该文件，则删除本地文件
                                try:
                                    if os.path.exists(event.src_path):
                                        os.remove(event.src_path)
                                        self.sync_logger.info(f"服务器优先策略: 删除本地文件 {rel_path}")
                                except Exception as del_e:
                                    self.sync_logger.error(f"删除本地文件失败: {str(del_e)}")
                            else:
                                raise
                except Exception as e:
                    self.sync_logger.error(f"处理服务器优先策略失败: {str(e)}")
            else:
                # 本地优先：同步到服务器
                if event.is_directory:
                    try:
                        self._retry_operation(lambda: self.syncer.ensure_remote_dir(rel_path))
                        self.sync_logger.info(f"目录创建同步成功: {rel_path}")
                        # 记录同步历史
                        self.syncer.record_sync_history(os.path.basename(rel_path), 'local_to_server', 'create_dir')
                    except Exception as e:
                        self.sync_logger.error(f"目录创建同步失败: {str(e)}")
                else:
                    # 等待文件写入完成
                    max_wait_time = 5.0  # 最大等待时间
                    wait_interval = 0.5  # 检查间隔
                    total_wait_time = 0
                    
                    # 在等待期间，暂时忽略修改事件
                    if not hasattr(self, '_pending_creates'):
                        self._pending_creates = set()
                    self._pending_creates.add(event.src_path)
                    
                    while total_wait_time < max_wait_time:
                        if os.path.exists(event.src_path):
                            try:
                                file_size = os.path.getsize(event.src_path)
                                if file_size > 0:  # 文件有内容
                                    break
                            except Exception as e:
                                self.sync_logger.error(f"检查文件大小失败: {str(e)}")
                                break
                        
                        time.sleep(wait_interval)
                        total_wait_time += wait_interval
                    
                    if os.path.exists(event.src_path):
                        if total_wait_time >= max_wait_time:
                            self.sync_logger.info(f"等待文件写入超时，但仍将同步文件: {rel_path}")
                        # 强制设置为创建操作
                        self._retry_operation(lambda: self.syncer.sync_file(rel_path, 'create', force_create=True))
                        # 记录同步历史
                        self.syncer.record_sync_history(os.path.basename(rel_path), 'local_to_server', 'create')
                    else:
                        self.sync_logger.warning(f"文件不存在，可能是临时文件: {event.src_path}")
                    
                    # 从待处理集合中移除
                    if event.src_path in self._pending_creates:
                        self._pending_creates.remove(event.src_path)

        except Exception as e:
            self.sync_logger.error(f"处理创建事件失败: {str(e)}")

    def on_modified(self, event):
        """处理修改事件"""
        try:
            # 获取本地路径
            local_path = self.get_local_path()
            if not local_path:
                self.sync_logger.error("无法获取本地路径")
                return
                
            # 获取相对路径
            rel_path = os.path.relpath(event.src_path, local_path)
            self.sync_logger.info(f"开始处理修改事件: path={event.src_path}")
            
            # 检查是否在忽略列表中
            if self._should_ignore(event.src_path):
                self.sync_logger.info(f"忽略修改事件: {rel_path}")
                return
                
            # 检查是否正在处理事件
            if not self._should_process_event(event.src_path, 'modified'):
                self.sync_logger.info(f"当前正在处理其他事件，忽略修改事件: {rel_path}")
                return
                
            # 获取同步策略
            if not self.syncer:
                self._init_syncer()
            strategy = self.syncer.sync_info['sync_strategy']
            self.sync_logger.info(f"当前同步策略: {strategy} (dir_id={self.sync_dir_id})")
            
            # 检查服务器上是否存在该文件
            remote_exists = False
            try:
                remote_files = self.syncer.list_remote_files()
                remote_exists = rel_path in remote_files
            except Exception as e:
                self.sync_logger.error(f"检查远程文件失败: {str(e)}")
                return
            
            # 根据文件是否存在决定操作类型
            operation = 'modify' if remote_exists else 'create'
            
            # 执行同步
            self.syncer.sync_file(rel_path, operation)
            
        except Exception as e:
            self.sync_logger.error(f"处理修改事件失败: {str(e)}")

    def on_deleted(self, event):
        """处理删除事件"""
        try:
            # 获取相对路径
            rel_path = self.get_relative_path(event.src_path)
            self.sync_logger.info(f"开始处理删除事件: path={event.src_path}, is_directory={event.is_directory}")
            
            # 检查是否在忽略列表中
            if self._should_ignore(event.src_path):
                self.sync_logger.info(f"忽略删除事件: {rel_path}")
                return
                
            # 检查是否正在处理事件
            if not self._should_process_event(event.src_path, 'deleted'):
                return
                
            # 获取同步策略
            strategy = self.syncer.sync_info['sync_strategy']
            self.sync_logger.info(f"当前同步策略: {strategy} (dir_id={self.sync_dir_id})")
            
            # 检查是否是文件替换操作
            is_replacement = False
            if hasattr(self, '_deleted_files') and event.src_path in self._deleted_files:
                is_replacement = True
                self.sync_logger.info(f"检测到可能的文件替换操作，暂时不处理删除事件: {rel_path}")
                return
                
            # 延迟处理删除事件，等待可能的文件替换操作完成
            threading.Timer(5, self.delayed_delete, args=(event.src_path, event.is_directory)).start()
            
        except Exception as e:
            self.sync_logger.error(f"处理删除事件失败: {str(e)}")

    def on_moved(self, event):
        """处理移动/重命名事件"""
        if self._should_ignore(event.src_path) or self._should_ignore(event.dest_path):
            return

        if not self._should_process_event(event.src_path, 'moved') or not self._should_process_event(event.dest_path,
                                                                                                     'moved'):
            return

        try:
            src_rel_path = self.get_relative_path(event.src_path)
            dest_rel_path = self.get_relative_path(event.dest_path)

            self.sync_logger.info(
                f"开始处理移动事件: path={event.src_path} -> {event.dest_path}, is_directory={event.is_directory}")

            # 检查是否应该执行同步
            if not self._should_sync():
                self.sync_logger.info(f"跳过同步，等待用户选择同步策略 (path={event.src_path} -> {event.dest_path})")
                return

            # 检查同步策略
            if not self.syncer:
                self._init_syncer()
            strategy = self.syncer.sync_info['sync_strategy']

            if strategy == 'server_priority':
                # 服务器优先：忽略本地移动，从服务器同步
                try:
                    if not event.is_directory:
                        self._retry_operation(lambda: self.syncer.sync_from_server(dest_rel_path))
                except Exception as e:
                    if 'No such file' in str(e) or '550' in str(e):
                        # 如果服务器上不存在该文件，则删除本地文件
                        try:
                            if os.path.exists(event.dest_path):
                                if event.is_directory:
                                    os.rmdir(event.dest_path)
                                else:
                                    os.remove(event.dest_path)
                                self.sync_logger.info(f"服务器优先策略: 删除本地文件 {dest_rel_path}")
                        except Exception as del_e:
                            self.sync_logger.error(f"删除本地文件失败: {str(del_e)}")
            else:
                # 本地优先：同步移动操作到服务器
                if event.is_directory:
                    try:
                        self._retry_operation(lambda: self.syncer.rename_remote_dir(src_rel_path, dest_rel_path))
                        self.sync_logger.info(f"目录移动同步成功: {src_rel_path} -> {dest_rel_path}")
                        # 记录同步历史
                        self.syncer.record_sync_history(
                            f"{os.path.basename(src_rel_path)} -> {os.path.basename(dest_rel_path)}",
                            'local_to_server',
                            'move_dir'
                        )
                    except Exception as e:
                        self.sync_logger.error(f"目录移动同步失败: {str(e)}")
                else:
                    try:
                        self._retry_operation(lambda: self.syncer.move_on_server(src_rel_path, dest_rel_path))
                    except Exception as e:
                        self.sync_logger.error(f"文件移动同步失败: {str(e)}")
                        # 如果移动失败，尝试删除后重新上传
                        try:
                            self._retry_operation(lambda: self.syncer.delete_from_server(src_rel_path))
                            time.sleep(0.5)  # 等待删除操作完成
                            self._retry_operation(lambda: self.syncer.sync_file(dest_rel_path, 'create'))
                        except Exception as e2:
                            self.sync_logger.error(f"文件移动备用方案失败: {str(e2)}")

        except Exception as e:
            self.sync_logger.error(f"处理移动事件失败: {str(e)}")

    def get_local_path(self):
        """获取同步目录的本地路径"""
        try:
            with db_manager.get_connection() as db:
                row = db.execute(
                    'SELECT local_path FROM sync_dirs WHERE id = ?',
                    (self.sync_dir_id,)
                ).fetchone()
                if row:
                    # 统一使用正斜杠
                    local_path = row['local_path'].replace('\\', '/')
                    self.sync_logger.debug(f"获取本地路径成功: sync_dir_id={self.sync_dir_id}, local_path={local_path}")
                    return local_path
                else:
                    self.sync_logger.error(f"找不到同步目录: sync_dir_id={self.sync_dir_id}")
                    return None
        except Exception as e:
            self.sync_logger.error(f"获取本地路径失败: {str(e)}")
            return None

    def delayed_delete(self, path, is_directory=False):
        """延迟处理删除事件"""
        try:
            # 获取相对路径
            rel_path = os.path.relpath(path, self.local_path)
            self.sync_logger.info(f"延迟处理删除事件: {rel_path}")
            
            # 检查服务器上是否存在该文件
            remote_exists = False
            try:
                # 使用list_remote_files方法检查文件是否存在
                remote_files = self.syncer.list_remote_files()
                remote_exists = rel_path in remote_files
            except Exception as e:
                self.sync_logger.error(f"检查远程文件失败: {str(e)}")
                return
            
            # 如果服务器上存在该文件，则删除
            if remote_exists:
                self.syncer.sync_file(rel_path, 'delete')
            else:
                self.sync_logger.info(f"服务器上不存在文件，无需删除: {rel_path}")
                
        except Exception as e:
            self.sync_logger.error(f"延迟处理删除事件失败: {str(e)}")